#pragma once
#include "noncopyable.h"

#include <vector>
#include <string>

/**
 * 这里buff的原理是，读和写起始index都是8
 * 然后两个均往后移，采用读index追赶写index的这种设计
 * 每次扩容的时候：
 *      缓存区内存不够，缓存区数组扩容
 *      缓存区内存够，读index归位8，写index前移
 */
class Buffer : Noncopyable
{

public:
    // 第一块空间大小
    static const size_t kCheapPrepend = 8;
    // 读加写空间大小
    static const size_t kInitialSize = 1024;

    explicit Buffer(size_t initialSize = kInitialSize)
        : buffer_(kCheapPrepend + initialSize), readIndex_(kCheapPrepend), writeIndex_(kCheapPrepend)
    {
    }

    // 预备/读/写空间大小
    size_t readableBytes() const { return writeIndex_ - readIndex_; }
    size_t writableBytes() const { return buffer_.size() - writeIndex_; }
    size_t prependableBytes() const { return readIndex_; }

    // 获取读起始指针
    const char *peek() const { return begin() + readIndex_; }

    // 占用读的len长度
    void retrieve(size_t len)
    {
        if (len < readableBytes())
        {
            readIndex_ += len;
        }
        else
        {
            // 等于的话fill全部
            // > 时候不考虑, 当=处理
            retrieveAll();
        }
    }

    void retrieveAll()
    {
        readIndex_ = writeIndex_ = kCheapPrepend;
    }

    // 读出读区的数据转为string返回
    std::string retrieveAllAsString() { return retrieveAsString(readableBytes()); }

    std::string retrieveAsString(size_t len)
    {
        std::string result(peek(), len);
        retrieve(len);
        return result;
    }

    // 确保写的长度够，不够就扩容
    void ensureWriteableBytes(size_t len)
    {
        if (writableBytes() < len) // 大于等于 不用处理，已经确保了
        {
            // 扩容len长度
            // 两种方式，一种往后续，一种挪位。采用哪种方式取决于buff内 空的（读index前面+写区）够不够
            makeSpace(len);
        }
    }

    void append(char *data, size_t len){
        ensureWriteableBytes(len);
        std::copy(data, data+len, beginWrite());
        writeIndex_ += len;
    }

    char* beginWrite(){return begin() + writeIndex_;}
    const char* beginWrite() const {return begin() + writeIndex_;}

    // 从fd上读数据
    ssize_t readFd(int fd, int* saveError);

    ssize_t writeFd(int fd, int* saveError);


private:
    // 起始指针
    char *begin() { return &*buffer_.begin(); }
    const char *begin() const { return &*buffer_.begin(); }

    void makeSpace(size_t len)
    {
        if (len > readIndex_ - kCheapPrepend + writableBytes())
        {
            // 直接往后续
            buffer_.resize(writeIndex_ + len);
        }
        else
        {
            // 只移动读数据，写区为空的不处理
            // 读写指针都移动
            size_t readBytes = readableBytes(); // 先取一份读区大小
            std::copy(begin() + readIndex_, begin() + writeIndex_, begin() + kCheapPrepend);
            readIndex_ = kCheapPrepend;
            writeIndex_ = kCheapPrepend + readBytes;
        }
    }

    // <(pre)----------(readIndex_)------------------(writeIndex_)---------------------->
    // 缓冲区
    std::vector<char> buffer_;
    // 读起始数组索引
    size_t readIndex_;
    // 写起始数组索引
    size_t writeIndex_;
};
